package com.hdax.dm.controller;

import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hdax.dm.common.constant.ConstantData;
import com.hdax.dm.common.exception.DmException;
import com.hdax.dm.common.exception.DmLinkUserException;
import com.hdax.dm.entity.order.OrderCondition2Vo;
import com.hdax.dm.common.vo.order.OrderConditionVo;
import com.hdax.dm.common.vo.order.OrderInfoVo;
import com.hdax.dm.common.vo.order.SubmitOrderVo;
import com.hdax.dm.config.AlipayConfig;
import com.hdax.dm.config.RabbitMQConfig;
import com.hdax.dm.dto.CommonResponse;
import com.hdax.dm.dto.DtoUtil;
import com.hdax.dm.entity.item.DmItem;
import com.hdax.dm.entity.order.DmOrder;
import com.hdax.dm.entity.order.DmOrderLinkUser;
import com.hdax.dm.entity.scheduler.DmScheduler;
import com.hdax.dm.entity.scheduler.DmScheduler2;
import com.hdax.dm.entity.scheduler.DmSchedulerSeat;
import com.hdax.dm.entity.user.DmLinkUser;
import com.hdax.dm.entity.user.DmUser;
import com.hdax.dm.feign.order.DmOrderFeign;
import com.hdax.dm.feign.order.DmOrderLinkUserFeign;
import com.hdax.dm.feign.scheduler.DmScheduler2Feign;
import com.hdax.dm.feign.scheduler.DmSchedulerFeign;
import com.hdax.dm.feign.user.DmLinkUserFeign;
import com.hdax.dm.service.DmOrderService;
import com.hdax.dm.utils.IdWorker;
import org.springframework.amqp.core.MessageDeliveryMode;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping(path = "/order")
public class DmOrderController {

    @Autowired
    private DmLinkUserFeign dmLinkUserFeign;
    @Autowired
    private DmOrderService dmOrderService;
    @Autowired
    private RedisTemplate<String,String> redisTemplate;
    @Autowired
    private DmScheduler2Feign dmScheduler2Feign;
    @Autowired
    private DmOrderFeign dmOrderFeign;
    @Autowired
    private DmOrderLinkUserFeign dmOrderLinkUserFeign;
    @Autowired
    private DmSchedulerFeign dmSchedulerFeign;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private RabbitMQConfig rabbitConfig;

    //局部异常处理
    @ExceptionHandler(value = {RuntimeException.class})
    public CommonResponse exceptionHandler(DmException exception){
        return DtoUtil.returnFail(exception.getErrorCode(), exception.getErrorMsg());
    }

    //返回常用联系人
    @PostMapping(path = "/permission/ticketbuyerlist")
    public CommonResponse<List<DmLinkUser>> ticketbuyerlist(HttpServletRequest request) throws JsonProcessingException {
        //获取用户信息
        String token = request.getHeader("token");
        ObjectMapper objectMapper = new ObjectMapper();
        DmUser dmUser = objectMapper.readValue(redisTemplate.opsForValue().get(token),DmUser.class);

        return DtoUtil.returnSuccess(dmLinkUserFeign.findLinkUserByuserId(dmUser.getId()));
    }

    //验证购票人是否已经存在
    @PostMapping(path = "/permission/validatebuyerexist")
    public CommonResponse<String> validatebuyerexist(@RequestBody Map<String,String> params){
        DmLinkUser dmLinkUser = dmLinkUserFeign.linkUserisExist(params.get("idCard"));
        if (dmLinkUser!=null){
            throw new DmLinkUserException(ConstantData.ErrCode.NULL_LINKUSER_EXIST_CODE,ConstantData.ErrMsg.NULL_LINKUSER_EXIST_MSG);
        }
        return DtoUtil.returnSuccess("购票人信息已存在");
    }

    //添加联系人
    @PostMapping(path = "/permission/addticketbuyer")
    public CommonResponse<String> addticketbuyer(@RequestBody DmLinkUser dmLinkUser,
                                                 HttpServletRequest request) throws JsonProcessingException {
        //获取用户信息
        String token = request.getHeader("token");
        ObjectMapper objectMapper = new ObjectMapper();
        DmUser dmUser = objectMapper.readValue(redisTemplate.opsForValue().get(token),DmUser.class);

        dmLinkUser.setUserId(dmUser.getId());
        return DtoUtil.returnSuccess(dmLinkUserFeign.addLinkUser(dmLinkUser));
    }

    //删除购票人
    @PostMapping(path = "/permission/deleteticketbuyer")
    public CommonResponse<String> deleteticketbuyer(@RequestBody Map<String,Long> params){
        dmLinkUserFeign.deleteLinkUser(params.get("linkId"));
        return DtoUtil.returnSuccess("删除成功");
    }

    //下单
    @PostMapping(path = "/permission/submitorder")
    public CommonResponse<Map<String,String>> submitorder(@RequestBody SubmitOrderVo orderVo) throws Exception {
        System.out.println(orderVo);
        //加redis锁： 锁剧场
        //如果存在key flag false否则true
        boolean flag = redisTemplate.opsForValue().setIfAbsent(orderVo.getSchedulerId()+"_lock","lock",2, TimeUnit.SECONDS);
        while (!flag){
            flag = redisTemplate.opsForValue().setIfAbsent(orderVo.getSchedulerId()+"_lock","lock",2, TimeUnit.SECONDS);
        }

        Double totalAmount = 0d;

        //校验下单的商品是否存在
        DmItem dmItem = dmOrderService.isExists(orderVo.getItemId());
        if(dmItem == null){
            //商品不存在下单失败
            throw new DmException("0003","商品不存在下单失败");
        }

        //创建订单对象
        DmOrder dmOrder = new DmOrder();
        dmOrder.setOrderNo(IdWorker.getId());           //订单号
        //dmOrder.setArea();                            //城市
        dmOrder.setOrderType(0L);                       //订单类型 (0:未支付 -1:支付超时/支付取消 2:已支付)

        //是否购买保险
        if (orderVo.getIsNeedInsurance() == 1L) {
            dmOrder.setInsuranceAmount(20d);
            totalAmount+=20d;
        }

        //设置属性
        dmOrder.setInvoiceType(orderVo.getInvoiceType());   //发票类型
        dmOrder.setInvoiceHead(orderVo.getInvoiceHead());   //发票抬头
        dmOrder.setInvoiceNo(orderVo.getInvoiceId());       //发票号
        dmOrder.setItemId(dmItem.getId());                  //商品id
        dmOrder.setItemName(dmItem.getItemName());          //商品名称
        dmOrder.setPayType(2L);                             //支付方式 支付宝支付
        dmOrder.setUserId(orderVo.getUserId());             //用户id
        dmOrder.setSchedulerId(orderVo.getSchedulerId());   //排期信息

        //首次拆分座位和订单联系人
        String[] seatPositions = orderVo.getSeatPositions().split(",");
        String[] linkIds = orderVo.getLinkIds().split(",");

        //人票是否匹配
        if (orderVo.getLinkIds().length()==0){
            //人票不匹配
            throw new DmException("0001","人票不匹配");
        }
        if(seatPositions.length != linkIds.length){
            //人票不匹配
            throw new DmException("0001","人票不匹配");
        }

        Double[] prices = new Double[linkIds.length];//座位价格集合

        //获得每一张票的具体信息
        //x_y,x_y
        for (int i = 0; i < seatPositions.length; i++) {
            //拆分座位信息
            Long x = Long.parseLong(seatPositions[i].split("_")[0]);
            Long y = Long.parseLong(seatPositions[i].split("_")[1]);
            //获取该座位信息
            DmScheduler2 condition = new DmScheduler2();
            condition.setScheduleId(orderVo.getSchedulerId());
            condition.setX(x);
            condition.setY(y);
            DmScheduler2 scheduler2 = dmScheduler2Feign.findSeat(condition);
            //判断座位是否可选
            if (scheduler2.getStatus()!=1){
                throw new DmException("0002","该座位已出售或已被锁定，请重选");
            }
            //给座位价格集合和最终价格赋值赋值
            prices[i] = scheduler2.getPrice();
            totalAmount+= scheduler2.getPrice();
        }

        dmOrder.setTotalCount(Long.valueOf(seatPositions.length));  //总数量
        dmOrder.setTotalAmount(totalAmount);                        //总价格

        //添加订单到数据库，如果出现问题，则需要回滚
        try {
            dmOrderFeign.addOrder(dmOrder);
        }catch (Exception e){
            System.out.println(e);
            rabbitTemplate.convertAndSend("tx_exchange","order_add",dmOrder.getOrderNo());
        }


        //添加订单联系人
        for (int i = 0; i < linkIds.length; i++) {
            //获取联系人信息
            Long linkId = Long.parseLong(linkIds[i]);//联系人主键
            DmLinkUser dmLinkUser = dmLinkUserFeign.findById(linkId);
            if(dmLinkUser == null){
                rabbitTemplate.convertAndSend("tx_exchange","order_add",dmOrder.getOrderNo());
                //订单联系人不存在
                throw new DmException("0001","订单联系人不存在");
            }
            //DmLinkUser -》 设置DmOrderLinkUser
            DmOrderLinkUser dmOrderLinkUser = new DmOrderLinkUser();
            dmOrderLinkUser.setOrderId(dmOrder.getOrderNo());
            dmOrderLinkUser.setLinkUserId(linkId);
            dmOrderLinkUser.setLinkUserName(dmLinkUser.getName());
            Long x = Long.parseLong(seatPositions[i].split("_")[0]);
            Long y = Long.parseLong(seatPositions[i].split("_")[1]);
            dmOrderLinkUser.setX(x);
            dmOrderLinkUser.setY(y);
            dmOrderLinkUser.setPrice(prices[i]);
            //添加订单联系人到数据库，如果出现问题，则需要回滚
            try{
                dmOrderLinkUserFeign.addOrderLinkUser(dmOrderLinkUser);
            }catch (Exception e){
                System.out.println(e);
                rabbitTemplate.convertAndSend("tx_exchange","order_add",dmOrder.getOrderNo());
                rabbitTemplate.convertAndSend("tx_exchange","order_link_user",dmOrder.getOrderNo());
            }
        }

        //获取每一个座位的信息
        for (int i = 0; i < seatPositions.length; i++) {
            Long x = Long.parseLong(seatPositions[i].split("_")[0]);
            Long y = Long.parseLong(seatPositions[i].split("_")[1]);
            DmSchedulerSeat dmSchedulerSeat = dmSchedulerFeign.getScheduleSeat(orderVo.getSchedulerId(),x,y);
            //修改订单号
            dmSchedulerSeat.setOrderNo(dmOrder.getOrderNo());
            //修改下单人id
            dmSchedulerSeat.setUserId(orderVo.getUserId());
            //修改座位状态
            //座位状态(0:没座位 1:有座位 2:锁定待付款 3:已售出 )
            dmSchedulerSeat.setStatus(2L);
            //修改座位信息到数据库，如果出现问题，则需要回滚
            try{
                dmSchedulerFeign.updateScheduleSeat(dmSchedulerSeat);
            }catch (Exception e){
                System.out.println(e);
                rabbitTemplate.convertAndSend("tx_exchange","order_add",dmOrder.getOrderNo());
                rabbitTemplate.convertAndSend("tx_exchange","order_link_user",dmOrder.getOrderNo());
                rabbitTemplate.convertAndSend("tx_exchange","schedule_seat",dmSchedulerSeat);
            }
        }

        //返回订单编号
        Map<String,String> result = new HashMap<>();
        result.put("orderNo",dmOrder.getOrderNo());

        //释放锁
        redisTemplate.delete(orderVo.getSchedulerId()+"_lock");
        //将订单信息添加到死信队列
        rabbitTemplate.convertAndSend(rabbitConfig.getOrder_exchange(),rabbitConfig.getOrder_routing_key(),dmOrder.getOrderNo(),message -> {
            message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);
            message.getMessageProperties().setExpiration("180000"); //订单超时时间
            return message;
        });
        return DtoUtil.returnSuccess(result);
    }

    //支付回调接口
    @RequestMapping(path = "/testPay")
    public void testPay(HttpServletRequest request, HttpServletResponse response) throws IOException {

        //交易金额 交易时间 暂未用到
        request.getParameter("total_amount");
        request.getParameter("timestamp");
        System.out.println(request);

        //修改座位为已售
        List<DmSchedulerSeat> dmSchedulerSeats = dmSchedulerFeign.getScheduleSeatbyOrderNo(request.getParameter("out_trade_no"));
        dmSchedulerSeats.forEach(dmSchedulerSeat -> {
            dmSchedulerSeat.setStatus(3L);
            dmSchedulerFeign.updateScheduleSeat(dmSchedulerSeat);
        });

        //修改订单状态为已支付
        DmOrder dmOrder = dmOrderFeign.findOrder(request.getParameter("out_trade_no"));
        dmOrder.setOrderType(2L);
        dmOrder.setAliTradeNo(request.getParameter("trade_no"));
        dmOrderFeign.updateOrder(dmOrder);

        //支付完成,返回首页
        System.out.println("异步通知完成！success");
        PrintWriter out = response.getWriter();
        out.print("<script>location.href='http://localhost:8080/'</script>");
    }

    //支付接口
    @GetMapping(path = "/pay")
    public String pay(@RequestParam("orderNo")String orderNo,
                      @RequestParam("itemName")String itemName,
                      @RequestParam("totalAmount")Double totalAmount) throws Exception{
        //根据订单编号查询订单详情
        //orderNo  title    最后一个属性用不到，自定义赋值
        OrderInfoVo orderInfoVo = new OrderInfoVo(orderNo,itemName,totalAmount,"无心");
        //获得初始化的AlipayClient
        AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.gatewayUrl, AlipayConfig.app_id, AlipayConfig.merchant_private_key, "json", AlipayConfig.charset, AlipayConfig.alipay_public_key, AlipayConfig.sign_type);

        //设置请求参数
        AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
        alipayRequest.setReturnUrl(AlipayConfig.return_url);
        alipayRequest.setNotifyUrl(AlipayConfig.notify_url);

        //设置支付信息
        alipayRequest.setBizContent("{\"out_trade_no\":\""+ orderInfoVo.getOrderNo() +"\","
                + "\"total_amount\":\""+ orderInfoVo.getTotalAmount() +"\","
                + "\"subject\":\""+ orderInfoVo.getSubject() +"\","
                + "\"body\":\""+ orderInfoVo.getDescription() +"\","
                + "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");

        //请求支付接口
        String result = alipayClient.pageExecute(alipayRequest).getBody();
        return result;
    }

    //返回全部订单
    @PostMapping(path = "/permission/queryorderlist")
    public CommonResponse<List<DmOrder>> queryorderlist(@RequestBody OrderConditionVo conditionVo,
                                                        HttpServletRequest request) throws JsonProcessingException {
        //获取用户信息
        String token = request.getHeader("token");
        ObjectMapper objectMapper = new ObjectMapper();
        DmUser dmUser = objectMapper.readValue(redisTemplate.opsForValue().get(token), DmUser.class);

        //将conditionVo的属性判断并拷贝至OrderCondition2Vo
        OrderCondition2Vo orderCondition2Vo = new OrderCondition2Vo();
        orderCondition2Vo.setUserId(dmUser.getId());
        SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Calendar calendar = Calendar.getInstance(); //创建Calendar 的实例
        //时间区间判断
        if (conditionVo.getOrderTime()==1){
            orderCondition2Vo.setEndTime(fmt.format(new Date()));
            calendar.add(Calendar.YEAR, -1);//当前时间减去一年，即一年前的时间
            orderCondition2Vo.setStartTime(fmt.format(calendar.getTime()));
        }else if (conditionVo.getOrderTime()==2){
            orderCondition2Vo.setEndTime(fmt.format(new Date()));
            calendar.add(Calendar.MONTH, -3);//当前时间减去一年，即一年前的时间
            orderCondition2Vo.setStartTime(fmt.format(calendar.getTime()));
        }
        //关键词判断
        if (conditionVo.getKeyword()!=null&&!conditionVo.getKeyword().equals("")){
            orderCondition2Vo.setKeyword(conditionVo.getKeyword());
        }
        if (conditionVo.getOrderType()!=null&&!conditionVo.getOrderType().equals("")){
            orderCondition2Vo.setOrderType(conditionVo.getOrderType());
        }

        return DtoUtil.returnSuccess(dmOrderFeign.findAllOrder(orderCondition2Vo));
    }
}
